A Brief Introduction to Git Commit Conventions
Most Git commit conventions on the internet today originate from the Angular team's format, which has evolved into many versions over time. Although this information is widely available, I decided to write an article to document it to prevent it from being lost—after all, the articles I read five years ago are no longer accessible. The current "[Angular Commit Format]" is as follows: (https://github.com/angular/angular/blob/main/CONTRIBUTING.md).
Commit Format
The Angular Commit Format is divided into three parts: header, body, and footer, separated by blank lines. The header is mandatory, the body depends on the header's type (mandatory if the type is docs), and the footer is optional.
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>Header
The header format is as follows (excerpted from the Angular Commit Format):
<type>(<scope>): <short summary>
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
│ elements|forms|http|language-service|localize|platform-browser|
│ platform-browser-dynamic|platform-server|router|service-worker|
│ upgrade|zone.js|packaging|changelog|docs-infra|migrations|
│ devtools
│
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|testType
The Type is used to categorize commits. Categories have varied over time; the current table is summarized below. The main differences are that style and chore have been removed, and CI/CD has been separated from build:
| Type | Description | New Description |
|---|---|---|
| feat | New feature | New feature |
| fix | Bug fix | Bug fix |
| docs | Documentation only changes | Documentation only changes |
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.) | |
| refactor | A code change that neither fixes a bug nor adds a feature | A code change that neither fixes a bug nor adds a feature |
| test | Adding missing tests or correcting existing tests | Adding missing tests or correcting existing tests |
| perf | A code change that improves performance | A code change that improves performance |
| build | Changes that affect the build system, CI configuration, or external dependencies (example scopes: gulp, broccoli, npm) | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) |
| chore | Other changes that don't modify src or test files | |
| ci | Changes to CI configuration files and scripts (example: CircleCI, SauceLabs) |
Scope
The Scope indicates the name of the affected npm package. This is defined specifically for Angular and may not apply to other programming languages. For me, in most cases, I choose to omit it or label it with the name of the project being changed.
Short Summary (Subject)
The Short Summary is a concise description of the changes. The Angular convention is as follows:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
However, since I write in Chinese, I simply omit the period at the end of the sentence.
Body
The original text from the Angular team is as follows:
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
Explain the motivation for the change in the commit message body. This commit message should explain why you are making the change. You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
Since I write in Chinese, there are no tense issues. In practice, unless the modification is complex or requires a specific explanation of the reason for the change, I omit the Body. Recently, a friend mentioned using Visual Studio's Copilot to help generate commit messages (if subscribed to Copilot); I might start using the generated messages as a base for the Body.
Footer
The Footer can contain breaking changes and deprecation information, and can also be used to reference GitHub issues, Jira tickets, and other PRs. For example:
BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
<BLANK LINE>
Fixes #<issue number>Or:
DEPRECATED: <what is deprecated>
<BLANK LINE>
<deprecation description + recommended update path>
<BLANK LINE>
<BLANK LINE>
Closes #<pr number>BREAKING CHANGE is used for major incompatible changes, and DEPRECATED is used to describe deprecated content.
In most cases, the Footer is only used to associate requirement ticket numbers, and the specific association method depends on the Issue Tracker used.
For example, in GitHub, you can use the following keywords to associate and close a PR with an issue. See the GitHub documentation "Linking a pull request to an issue".
- close
- closes
- closed
- fix
- fixes
- fixed
- resolve
- resolves
- resolved
In GitLab, you can use the following methods to link, replacing 123 with the corresponding ID:
- Associate Issue: #123
- Associate MR: !123
- Associate Snippet: $123
GitLab can also use Closes #123 or Fixes #123 to close the corresponding issue when merging the branch. See the GitLab documentation "Tutorial: It's all connected in GitLab".
Personally, since a PR or MR might not be associated with an Issue Tracker, or I might want to control the association manually, I use the prefix issue so that it is semantically clear that #123 is associated with an issue.
TIP
Keywords like close are case-insensitive. The examples in the documentation use uppercase because they appear at the beginning of a sentence; if you look closely at those appearing in the middle of a sentence, they are lowercase.
Commit Template
The above is a brief introduction to current mainstream commit conventions, but in actual operation, you might forget some less frequently used content. For example, I often forget some of the less common Types. Git supports a default Commit Template, which can help us standardize the commit message format.
Configuration Method
First, create a file named .gitmessage.txt. The filename cannot be changed. The content is as follows and can be adjusted according to your needs:
<type>(<scope>): <subject>
# -- Type --
# Must be one of the following:
#
# feat: New feature
# fix: Bug fix
# docs: Documentation only changes
# style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
# refactor: A code change that neither fixes a bug nor adds a feature
# perf: A code change that improves performance
# test: Adding missing tests or correcting existing tests
# build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
# chore: Other changes that don't modify src or test files
# ci: Changes to CI configuration files and scripts (example: CircleCI, SauceLabs)
#
# -- Scope --
# The scope can be anything specifying the location of the commit changes, e.g., init, runner, watcher, config, web-server, proxy, etc.
#
# -- Subject --
# The subject contains a concise description of the changes:
# Use the imperative, present tense: "change" not "changed" nor "changes"
# Do not capitalize the first letter
# Do not use a period at the end
#
# -- Body --
# Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes".
# The body should contain the motivation for the change and compare it with previous behavior.
#
# -- Footer --
# The footer should contain information about Breaking Changes and is also a reference for GitHub issue closing.
# Breaking Changes should start with the word "BREAKING CHANGE": followed by a space or two newlines. Then use the rest of the commit message.
# Deprecated should start with the word "DEPRECATED": followed by a space or two newlines. Then use the rest of the commit message.Next, open Git Bash and enter the following commands (where ~/ defaults to C:\Users\{Windows Account}, or replace ~/ with the full path where you want to place the file):
git config --global commit.template ~/.gitmessage.txt
git config --global commit.cleanup stripExplanation:
git config: This is the Git configuration command used to view and set Git configuration options.--global: This flag indicates that the setting will be used globally, i.e., for all Git repositories. If this flag is not used, the setting will only take effect in the current Git repository.commit.template: Used to specify the location of the commit message template file.commit.cleanup: Used to specify how to handle commit messages during a commit. The default iswhitespace, which does not ignore comment lines.strip: This is the value for thecommit.cleanupoption, which means that comment lines and extra blank lines in the commit message are removed during the commit.
After execution, the following content will be added to the global .gitconfig. The global .gitconfig is stored in the user account folder by default on Windows, e.g., C:\Users\{Windows Account}.
[commit]
cleanup = strip
template = {Specified Path}/.gitmessage.txtIf the command is entered without --global, this content will be generated in the ./.git/config file of that repository.
TIP
If template is set to ./.gitmessage.txt, Git will use the .gitmessage.txt file in the root directory of the repository as the Commit Template.
Git has three configuration levels:
- System configuration:
- Location:
C:\Program Files\Git\etc\gitconfig. - Lowest priority. This setting affects all users and projects on the entire system. It is usually a global setting configured by the system administrator, suitable for system-wide Git behavior conventions.
- Location:
- Global configuration:
C:\Users\{Windows Account}\.gitconfig:- Second highest priority. This setting applies to a single user but is overridden by Local settings. It is commonly used to set personal Git options and affects all repositories unless overridden by Local settings.
- Local configuration:
.git\config- Highest priority. This setting is only valid for the current project and overrides Global and System settings. Since its scope is limited to a specific repository, it is particularly useful for cases where special settings are needed for a project.
TIP
The three filenames are all different XD
Actual Usage
When you enter git commit in Git Bash, the message hint: Waiting for your editor to close the file... will appear, and a text editor will open containing the content of .gitmessage.txt along with the following information:
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch main
# Your branch is up to date with 'origin/main'.
#
# Changes to be committed:
# modified: "{Modified Filename}"The blank line added at the end of .gitmessage.txt is to separate it from this section of information. This section mainly explains that you should enter a commit message, that lines starting with # will be ignored, and provides a list of modified files.
Once you have modified the file and saved it, the content of the file will be used as the commit message.
If you use other Git version control software, it may not necessarily ignore lines starting with #, so you need to set commit.cleanup strip.
Currently, the version control software I know that supports Commit Template is as follows:
GitKraken: Click File => Preferences... => Commit on the repository tab to display the Commit Template settings. If
commit.cleanup stripis not set, remember to check "Removes comments from commit messages" to ignore lines starting with#.Tortoisegit: When
commit.cleanupiswhitespace, commits do not ignore lines starting with#.Git Extensions: When
commit.cleanupiswhitespace, commits still ignore lines starting with#(thanks to my colleague for testing).Sourcetree:
- Mac version 4.2.8 supports it (thanks to my colleague for testing); Windows version 3.4.20 and later support it.
- When
commit.cleanupiswhitespace, commits still ignore lines starting with#.
TIP
Sourcetree version 3.4.18 did not support Git Template, but I saw that on 2024/6/27, the official team closed the Jira ticket that everyone had been calling for for years, stating that it was resolved in Commit template message, so it might be supported in a later version.
Sourcetree 3.4.20 has added support. See Sourcetree release notes.
SourceTree 3.4.20 [17 September 2024]
- Changes: Supporting git commit template feature
- Changes: Upgrade to Git 2.46.0 and Git LFS to 3.5.1
- Fixed: 'Push changes immediately' checkbox is disabled in No Staging View
- Fixed: Arbitrary code execution vulnerability
- Fixed: Interactive rebase always aborting when a merge is necessary
- Fixed: Silent crash when creating a hotfix
- Fixed: Sourcetree diff treats large .sql files as binary
- Fixed: Windows Line breaks are replaced with Unix breaks on "Discard Hunk" click
Reverting Settings
You can use the following command to remove the Git Template setting:
git config --unset --global commit.templateUse the following command to restore the setting to ignore comment lines:
git config --global commit.cleanup whitespaceChange Log
- 2024-07-23 Initial document creation.
- 2024-09-20
- Updated to reflect that Windows Sourcetree 3.4.20 supports the Git Commit Template feature.
- Corrected the explanation of configuration file locations.